package com.cqs.learning.spring.cloud.producer.aop;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 熔断降级切面
 *
 * @author lixw
 * @date created in 20:13 2020/4/1
 */
@Aspect
@Log4j2
@Component
public class DegradeAspect {


    @Pointcut("execution(public * com.cqs.learning.spring.cloud.producer.service.impl.DegradeServiceImpl.*(..))")
    //@Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
    public void degradePointCut() {

    }


    @Around("degradePointCut()")
    public Object invoke(ProceedingJoinPoint pjp) throws BlockException {
        Signature signature = pjp.getSignature();
        if (!(signature instanceof MethodSignature)) {
            throw new RuntimeException("不合法的方法签名" + signature);
        }
        MethodSignature ms = (MethodSignature) signature;
        Method method = ms.getMethod();
        SentinelResource sentinelResource = method.getAnnotation(SentinelResource.class);
        Object result = null;
        if (sentinelResource != null) {
            //添加熔断逻辑
            String resource = sentinelResource.value();
            log.info("resource:{}", resource);
            try (Entry entry = SphU.entry(resource)) {
                try {
                    result = pjp.proceed(pjp.getArgs());
                } catch (Throwable throwable) {
                    if (!(throwable instanceof RuntimeException)) {
                        throwable.printStackTrace();
                    }
                    //上手业务方
                    if (throwable instanceof DegradeException) {
                        throw (DegradeException) throwable;
                    }

                    //这里一定要使用Tracer.trace(throwable) =，否则熔断不会生效
                    Tracer.trace(throwable);
                }
            } finally {

            }
        }
        return result;
    }
}
